import urllib
import urllib2
import json
import os
import time
import sys
import datetime
import unicodedata
import re
from twitter.api import Twitter, TwitterError
from twitter.oauth import OAuth, write_token_file, read_token_file
from twitter.oauth_dance import oauth_dance
from random import Random
#from datetime import datetime, date, time, timedelta
CONSUMER_KEY='uS6hO2sV6tDKIOeVjhnFnQ'
CONSUMER_SECRET='MEYTOS97VvlHX7K1rwHPEqVpTSqZ71HtvoK4sVuYk'
SEEN_FILENAME = 'seen.txt'
REDDITS = ['http://www.reddit.com/.json', 'http://www.reddit.com/r/aww/.json']
USER = 'jckwsh'
RMAPPINGS = {'science':'http://www.reddit.com/r/science/.json', 'biology':'http://www.reddit.com/r/science/.json', 'chemistry':'http://www.reddit.com/r/science/.json', 'physics':'http://www.reddit.com/r/science/.json', 'astronomy':'http://www.reddit.com/r/science/.json', 'music':'http://www.reddit.com/r/Music/.json', 'technology':'http://www.reddit.com/r/technology/.json', 'computer':'http://www.reddit.com/r/technology/.json', 'computers':'http://www.reddit.com/r/technology/.json', 'internet':'http://www.reddit.com/r/technology/.json', 'tech':'http://www.reddit.com/r/technology/.json', 'geek':'http://www.reddit.com/r/geek/.json', 'movie':'http://www.reddit.com/r/movies/.json', 'movies':'http://www.reddit.com/r/movies/.json', 'film':'http://www.reddit.com/r/movies/.json', 'films':'http://www.reddit.com/r/movies/.json', 'actor':'http://www.reddit.com/r/movies/.json', 'actress':'http://www.reddit.com/r/movies/.json', 'sports':'http://www.reddit.com/r/sports/.json', 'sport':'http://www.reddit.com/r/sports/.json', 'hockey':'http://www.reddit.com/r/hockey/.json', 'nhl':'http://www.reddit.com/r/hockey/.json'}
targets = []

class r2t:
  rUrl = 'http://www.reddit.com/.json'
  bitlyLogin = 'r2tb'
  bitlyApiKey = 'R_45323c678466965420f0375702034a7a'
  seen = []
  profanity = []
  
  def __init__(self):
    try:
      with file(SEEN_FILENAME, 'r') as f:
        for line in f:
          self.seen.append(line[:-1])
    except IOError:
      self.seen = []
    try:
      with file('profanity.txt', 'r') as f:
        for line in f:
          self.profanity.append(line[:-1])
    except IOError:
      self.profanity = []

  def getPost(self, rUrl, rank):
    url = urllib2.urlopen(rUrl)
    jsonstr = url.read()
    jsonobj = json.loads(jsonstr)
    jsondata = jsonobj[u'data']
    jsonchildren = jsondata[u'children']
    topPost = jsonchildren[rank]
    topPostData = topPost[u'data']
    title = unicodedata.normalize('NFKD', topPostData[u'title']).encode('ascii', 'ignore')
    title = title.rstrip(None)
    for word in self.profanity:
      if title.lower().find(word) >= 0:
        return None
    titleSplit = re.findall(r'\w+', title.lower())
    talksAboutSelf = 'i' in titleSplit or 'me' in titleSplit or 'my' in titleSplit or 'reddit' in titleSplit
    if topPostData[u'is_self'] == True or topPostData[u'over_18'] == True or title in self.seen or talksAboutSelf :
      log('Post was no good, self: ' + str(topPostData[u'is_self']) + ' NSFW: ' + str(topPostData[u'over_18']) + ' seen: ' + str(title in self.seen) + ' talks about self : ' + str(talksAboutSelf))
      return None
    
    self.seen.append(title)
    with file(SEEN_FILENAME, 'a') as f:
      f.write(title + '\n')      
    return topPostData

  def postTitle(self, post):
    title = unicodedata.normalize('NFKD', post[u'title']).encode('ascii', 'ignore')
    if title[-1] == '.' or title[-1] == ',':
      title = title[:-1]
    return title

  def postUrl(self, post):
    return str(post[u'url'])

  def rpostUrl(self, post):
    return 'http://www.reddit.com' + str(post[u'permalink'])

  def bitlyzer(self, url):
    login = urllib.urlencode(dict(login = self.bitlyLogin))
    apiKey = urllib.urlencode(dict(apiKey = self.bitlyApiKey))
    longUrl = urllib.urlencode(dict(longUrl = url))
    enUrl = 'http://api.bit.ly/shorten?%s&%s&%s&format=json' % (login, apiKey, longUrl)
    request = urllib2.urlopen(enUrl)
    response = request.read()
    rtable = eval(response)
    results = rtable['results']
    thisRun = results[url]
    shortUrl = thisRun['shortUrl']
    return shortUrl

  def parsePost(self, post):
    linkUrl = self.bitlyzer(self.postUrl(post))
    title = self.postTitle(post)
    link = ': ' + linkUrl
    if len(title) + len(link) > 140:
      li = (140 - len(link)) - 5
      title = title[:li] + '...'
    tpost = title + link
    return tpost

def follow(twit, tid):
  try:
    if(tid <488):
      tid = targets[tid]    
      if (twit.friendships.exists(user_a = USER, user_b = tid) == False):
        log("Trying to Follow Someone")
        twit.friendships.create(user_id = tid)
        if datetime.datetime.now().day == 27:
          user_name = twit.users.lookup(user_id = tid)[0][u'screen_name']
          update = "#FF Follow Friday @" + user_name
          twit.statuses.update(status= update)
        log("Followed user: " + str(tid))
    else:
      followFollowers(twit)
    
  except TwitterError as e:
    log("Follow Error: " + str(type(e)))
  
def followFollowers(twit):
  if(twit.account.rate_limit_status() < 100):
    followers = twit.friends.ids(screen_name = USER)
    followed = twit.followers.ids(screen_name = USER)
    for follower in followers:
      if followed.count(follower) == 0:
        twit.friendships.create(id = follower)
      
def findOpponents(t, position):
  user = targets[position]
  user = int(user.rstrip(None))
  followers = t.friends.ids(user_id = user)
  for follower in followers:
    if TARGET_FOLLOWERS.has_key(follower):
      TARGET_FOLLOWERS[follower][0] = TARGET_FOLLOWERS[follower][0] + 1
    else:
      TARGET_FOLLOWERS[follower][0] = 1  
      #print len(TARGET_FOLLOWERS)
  #print userids

def bottick(t):
  #Stop if time is Tuesday May 31 2011, 1:30pm

  rapture = datetime.datetime(2011, 5, 31, 13, 30)
  rand = Random(rapture.microsecond)
  bot = r2t()
  target_position = 0
  #post randomly between 1 minute and 2 hours
  postdate = datetime.datetime.now()# + datetime.timedelta(microseconds = rand.randint(900000000, 7200000000))
  post = None
  lastdate = datetime.datetime.now()
  follow_position = len(t.friends.ids(screen_name = USER))
  min_postTime = 2 * 60000000 #2 minutes
  max_postTime = 75 * 60000000 #75 minutes
  while datetime.datetime.now() <= rapture:
    try:
      if (t.account.rate_limit_status(screen_name = USER) < 350):
        continue  
      if (datetime.datetime.now() >= postdate):
        if (postdate.hour > 4 and postdate.hour < 23):
          log('Time to post, lets find something')
          post = findPost(bot)
          if post != None:
            tpost = bot.parsePost(post)
            log('Parsed post, result: ' + tpost + ' len = ' + str(len(tpost)))
            t.statuses.update(status=tpost)
            log('Posting: ' + tpost)
        else:
          if(rand.randint(0,100) < 10):
            log('Too late to post, trying random post')
            post = findPost(bot)
            if post != None:
              tpost = bot.parsePost(post)
              log ('Parsed post')
              t.statuses.update(status=tpost)
              log('Posting: ' + tpost)
          else:
            log('Too late to post, doing research')
            target_position = research(t, target_position)
        postdate = datetime.datetime.now() + datetime.timedelta(microseconds = rand.randint(min_postTime, max_postTime))
        log("Next posting time is: " + str(postdate))
      elif datetime.datetime.now() > lastdate + datetime.timedelta(seconds=45):
        log('Posted too recently, doing research')
        research(t, target_position)
        lastdate = datetime.datetime.now()
        if follow_position < 500:
          ran = rand.randint(0, 100)
          log("Attempting Follow chance result: " + str(ran) + " " + follow_position)
          if ran <= 30:  
            follow(t, follow_position)
            follow_position = follow_position + 1
    except TwitterError as e:
      log("Twitter BotTick: " + str(type(e)))
    except Exception as e:
      log("BotTick: " + str(type(e)) + e.message)

def findPost(bot):
  post = None
  for i in range(0,len(REDDITS)):
    for j in range(0,6): 
      if post != None:
        return post
      log('Trying to find new post in: ' + str(REDDITS[i]) + ' rank: ' + str(j))
      post = bot.getPost(REDDITS[i], j)

def research(t, position):
  rand = Random()
  findSubreddits(t)
  return position
  
def log(msg):
  with file('log.txt', 'a') as f:
    now = datetime.datetime.now()
    f.write('['+str(now.month)+'/'+str(now.day)+'/'+str(now.year)+' '+str(now.hour)+':'+str(now.minute)+':'+str(now.second)+'] '+str(msg)+'\n')
    
def findSubreddits(t):
  rng = Random()
  i = rng.randint(0,len(targets))
  try:
    timeline = t.statuses.user_timeline(user_id=int(targets[i]))
    log('Investigating user with user_id: ' + targets[i])
    #grab 5 most recent tweets as sample
    sample = timeline[:4]
    for post in sample:
      text = unicodedata.normalize('NFKD', post[u'text']).encode('ascii', 'ignore')
      for word in text.split():
        if word in RMAPPINGS:
          if not RMAPPINGS[word] in REDDITS:
            REDDITS.append(RMAPPINGS[word])
            with file('reddits.txt', 'a') as f:
              f.write(RMAPPINGS[word] + '\n')
            log('Found new subreddit to add: ' + RMAPPINGS[word])
            log('Matched word ' + word + ' in status ' + text + ' (from user_id: ' + targets[i] + ')')
  except TwitterError as e:
    log("Error finding subreddits User:" + targets[i])    
  except Exception as e:
    log("Subreddit Error:" + str(type(e)) + targets[i])
    
if __name__ == '__main__':
  #hack to wipe out the old log
  f = file('log.txt', 'w')
  f.close()
  try:
    with file('targets.txt', 'r') as f:
      for line in f:
        targets.append(line[:-1])
  except IOError:
    targets = []
  try:
    with file('reddits.txt', 'r') as f:
      for line in f:
        REDDITS.append(line[:-1])
  except IOError:
    None
    #don't need to do anything REDDITS already has default vals
  oauth_token, oauth_token_secret = read_token_file('toauth')
  t = Twitter(auth=OAuth(oauth_token, oauth_token_secret, CONSUMER_KEY, CONSUMER_SECRET), secure=True, api_version='1', domain='api.twitter.com')
  bottick(t)
